﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Drawing;
using LightCAD.Runtime;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QdArch
{
    public partial class WindowAction : ElementAction
    {
        private ElementInputer ElementInputer { get; set; }

        public WindowAction() { }
        public WindowAction(DocumentRuntime docRt) : base(docRt)
        {
            docRt.CommandCtrl.WriteInfo("命令：Window");
        }

        internal static void Initilize()
        {
            ArchActions.WindowAction = new WindowAction();
            LcDocument.ElementActions.Add(ArchElementType.Window, ArchActions.WindowAction);
        }

        public async void ExecCreate(string[] args = null)
        {
            //1. 选择元素
            //2. 选择门窗类型
            this.ElementInputer = new ElementInputer(this.docRt);
        Step0:
            var result = await this.ElementInputer.Execute("选择墙体:");
            if (result == null || result.Value == null || !(result.Value is QdWall))
            {
                goto Step0;
            }

        Step1:
            string doorName = "ThreeLine";
            var instP = (Vector2d)result.Extent;
            var wall = (QdWall)result.Value;
            var wallLine = wall.BaseLine;
            var isLineRight = IsRight(wallLine.Start, wallLine.End, instP);
            var window = docRt.Document.Components.Find(ArchCategory.Door.ToString(), doorName) as QdWindow;
            if (window == null)
            {
                window = new QdWindow(DoorCategory.SwingDoor.ToString(), doorName);
            }

            var pset = QdWindow.ParamsDefinition.New();
            pset["Thickness"] = wall.Width;
            pset["Width"] = 900.0;
            pset["Height"] = 1500.0;
            pset["BottomOffset"] = 0;
            pset["IsLeft"] = false;
            pset["IsNear"] = isLineRight;

            var projectP = wallLine.Projection(instP);

            var windowRef = this.docRt.Document.CreateObject<QdWindowRef>();
            windowRef.Parameters = pset;
            windowRef.InsertPoint = projectP;
            windowRef.Window = window;
            windowRef.Wall = wall;
            windowRef.Thickness = 50;
            windowRef.Width = (double)pset["Width"];
            windowRef.Height = (double)pset["Height"];
            windowRef.Bottom = 600.0;

            var wallLineDir = wallLine.Dir;
            var offset = wallLineDir * (windowRef.Width / 2);
            windowRef.StartPoint = windowRef.InsertPoint - offset;
            windowRef.EndPoint = windowRef.InsertPoint + offset;

            var isRight = !(bool)windowRef.Parameters["IsLeft"]; //是否在插入点右侧
            var isUp = !(bool)windowRef.Parameters["IsNear"]; //是否在墙线上方，即墙线左侧

            //第三个点的旋转角度， 经观察发现三个点在半径相同的同一个圆上，圆心为doorRef.InsertPoint
            double angle = wallLineDir.Angle();
            double angle45 = Math.PI / 4;
            if (isRight && isUp)
            {
                angle += angle45;
            }
            else if (!isRight && isUp)
            {
                angle += Math.PI / 2 + angle45;
            }
            else if (!isRight && !isUp)
            {
                angle += Math.PI + angle45;
            }
            else if (isRight && !isUp)
            {
                angle += Math.PI * 1.5 + angle45;
            }

            var lineDir = Vector2d.RotateInRadian(wallLineDir, angle);
            var lineOffset = lineDir * (windowRef.Width / 2);

            windowRef.ControlPoint = windowRef.InsertPoint + lineOffset;

            wall.AddLcComponent(windowRef, "Window", AssociateType.Cross);

            this.ElementInputer = null;
            this.EndCreating();
            this.DrawWindow(windowRef);
        }

        public override void Draw(SKCanvas canvas, LcElement element, Vector2d offset)
        {
            var windowRef = element as QdWindowRef;
            var shape2d = windowRef.Window.Shape2D;
            var wallLine = windowRef.Wall.BaseLine;

            var angle = wallLine.Dir.Angle();
            var matrix = Matrix3d.RotateInRadian(angle);

            matrix = Matrix3d.Translate(windowRef.InsertPoint) * matrix;


            //var shape = QdDoor.ShapeProvider.Shapes.GetShape(door.Name); 
            var curves = shape2d.Generate(windowRef.Parameters);

            var pen = this.GetDrawPen(element);
            if (pen == Constants.defaultPen)
            {
                //pen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true };
                pen = new SKPaint { Color = SKColors.Orange, IsStroke = true, /*PathEffect = Constants.SelectedEffect*/ };
            }
            foreach (var curve in curves)
            {
                switch (curve.Type)
                {
                    case Curve2dType.Line2d:
                        {
                            var line = curve as Line2d;
                            var wsp = matrix.MultiplyPoint(line.Start);
                            var wep = matrix.MultiplyPoint(line.End);

                            var ssp = this.vportRt.ConvertWcsToScr(wsp).ToSKPoint();
                            var sep = this.vportRt.ConvertWcsToScr(wep).ToSKPoint();
                            canvas.DrawLine(ssp, sep, pen);
                            break;
                        }
                    case Curve2dType.Arc2d:
                        {
                            var arc = curve as Arc2d;
                            
                            var wcenter = matrix.MultiplyPoint(arc.Center);
                            var scenter = this.vportRt.ConvertWcsToScr(wcenter).ToSKPoint();

                            var wrect = new Box2d(wcenter.X - arc.Radius, wcenter.Y - arc.Radius, arc.Radius * 2, arc.Radius * 2);
                            var plt = this.vportRt.ConvertWcsToScr(wrect.LeftTop);
                            var prb = this.vportRt.ConvertWcsToScr(wrect.RightBottom);
                            var scrRect = new SKRect((float)plt.X, (float)plt.Y, (float)prb.X, (float)prb.Y);
                            var sweep = arc.EndAngle - arc.StartAngle ;
                            //Skia绘制圆弧是按照顺时针的，与数学逻辑相反
                            canvas.DrawArc(scrRect, -(float)(arc.EndAngle + Utils.RadianToDegree(angle)), (float)sweep, false, pen);
                            break;
                        }
                    case Curve2dType.Polyline2d:
                        {
                            var pline = curve as Polyline2d;
                            var scrPoints = pline.Points.Select((p) => matrix.MultiplyPoint(p).ToSKPoint()).ToArray();
                            canvas.DrawPoints(SKPointMode.Polygon, scrPoints, pen);
                            break;
                        }
                    case Curve2dType.Polygon2d:
                        {
                            var polygon = curve as Polygon2d;
                            var scrPoints = polygon.Points.Select((p) => matrix.MultiplyPoint(p).ToSKPoint()).ToList();
                            scrPoints.Add(scrPoints[0]);
                            canvas.DrawPoints(SKPointMode.Polygon, scrPoints.ToArray(), pen);
                            break;
                        }
                    default:
                        break;
                }
            }
        }


        public void DrawWindow(QdWindowRef windowRef)
        {
            this.docRt.Document.ModelSpace.InsertElement(windowRef);
            this.docRt.Action.ClearSelects();
        }

        #region Grip
        private QdWindowRef _windowRef;
        private string _gripName;
        private Vector2d _position;

        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var windowRef = element as QdWindowRef;
            var grips = new List<ControlGrip>();

            var gripCenter = new ControlGrip
            {
                Element = windowRef,
                Name = "Center",
                Position = windowRef.InsertPoint
            };
            grips.Add(gripCenter);

            var wallLine = windowRef.Wall.BaseLine;
            var gripLeft = new ControlGrip
            {
                Element = windowRef,
                Name = "Left",
                Position = windowRef.StartPoint
            };
            grips.Add(gripLeft);

            var gripRight = new ControlGrip
            {
                Element = windowRef,
                Name = "Right",
                Position = windowRef.EndPoint
            };
            grips.Add(gripRight);

            
            var gripOpenDir = new ControlGrip
            {
                Element = windowRef,
                Name = "Control",
                Position = windowRef.ControlPoint
            };
            grips.Add(gripOpenDir);

            return grips.ToArray();
        }

        public override void SetDragGrip(LcElement element, string gripName, Vector2d position, bool isEnd)
        {
            var windowRef = element as QdWindowRef;
            _windowRef = windowRef;
            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                if (gripName == "Center")
                {
                    var offset = position - windowRef.InsertPoint;
                    windowRef.InsertPoint = position;
                    windowRef.StartPoint += offset;
                    windowRef.EndPoint += offset;
                    windowRef.ControlPoint += offset;
                }
            }
            
        }

        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_windowRef == null)
                return;

            var center = this.vportRt.ConvertWcsToScr(_windowRef.InsertPoint);
        }
        #endregion

        public bool IsRight(Vector2d start, Vector2d end, Vector2d p)
        {
            //Vsub(D,A,B) D.x=A.x-B.x; D.y=A.y-B.y
            Vector2d v1 = start - end;
            Vector2d v2 = p - start;

            double f = v1.X * v2.Y - v2.X * v1.Y;
            return f >= 0;
        }
    }
}
